package com.zhaoning.znojcodesandbox;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import com.zhaoning.znojcodesandbox.model.ExecuteCodeRequest;
import com.zhaoning.znojcodesandbox.model.ExecuteCodeResponse;
import com.zhaoning.znojcodesandbox.model.ExecuteMessage;
import com.zhaoning.znojcodesandbox.utils.ProcessUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author zhaoning
 * @Date 2025/3/8
 */
public class JavaNativeCodeSandbox {

    private static final String GLOBAL_CODE_PATH_NAME = "tmpCode";

    private static final String GLOBAL_JAVA_CLASS_NAME = "Main.java";

    private static final long TIME_OUT = 5000L;

    public static void main(String[] args) throws Exception {
        JavaNativeCodeSandbox javaNativeCodeSandbox = new JavaNativeCodeSandbox();
        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();
        executeCodeRequest.setInputs(Arrays.asList("444 2", "3 4"));
        String code = ResourceUtil.readStr("testCode/simpleComputeArgs/Main.java", StandardCharsets.UTF_8);
        executeCodeRequest.setCode(code);
        executeCodeRequest.setLanguage("java");
        ExecuteCodeResponse executeCodeResponse = javaNativeCodeSandbox.executeCode(executeCodeRequest);

    }

    public ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {
        List<String> inputs = executeCodeRequest.getInputs();
        String code = executeCodeRequest.getCode();
        String language = executeCodeRequest.getLanguage();

        // 1. 用户代码存成文件
        String userDir = System.getProperty("user.dir");
        String globalCodePathName = userDir + File.separator + GLOBAL_CODE_PATH_NAME;
        // 判断全局代码目录是否存在
        if (!FileUtil.exist(globalCodePathName)) {
            FileUtil.mkdir(globalCodePathName);
        }

        // 用户代码隔离存放
        String userCodePathName = globalCodePathName + File.separator + UUID.randomUUID() + File.separator + GLOBAL_JAVA_CLASS_NAME;
        File codeFile = FileUtil.writeString(code, userCodePathName, StandardCharsets.UTF_8);

        // 2. 编译代码，得到class文件
        String compileCmd = String.format("javac -encoding utf-8 %s", codeFile.getAbsolutePath());
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(compileCmd);
        } catch (IOException e) {
            return getErrorResponse(e);
        }

        ExecuteMessage em = null;
        try {
            em = ProcessUtil.runAndGetOutput(process, "编译");
        } catch (Exception e) {
            return getErrorResponse(e);
        }
        int exitCode = em.getExitCode();

        if (exitCode != 0) {
            return getErrorResponse(new RuntimeException("编译错误"));
        } else System.out.println("编译成功" + exitCode);

        // 逐行获取输出
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while (true) {
            try {
                if (!((line = bufferedReader.readLine()) != null)) break;
            } catch (IOException e) {
                return getErrorResponse(e);
            }
            sb.append(line);
        }
        System.out.println("ok: " + sb + ".");

        // 3. 执行代码，得到输出结果
        List<ExecuteMessage> emList = new java.util.ArrayList<>();
        for (String input : inputs) {
            String runCmd = String.format("java -Xmx256m -Dfile.encoding=UTF-8 -cp %s Main %s", codeFile.getParent(), input);
            Process runProcess = null;
            try {
                runProcess = Runtime.getRuntime().exec(runCmd);
            } catch (IOException e) {
                return getErrorResponse(e);
            }
            try {
                em = ProcessUtil.runAndGetOutput(runProcess, "运行");
                new Thread(() -> { // 超时自动停止
                    try {
                        Thread.sleep(TIME_OUT);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }).start();
            } catch (Exception e) {
                return getErrorResponse(e);
            } finally {
                runProcess.destroy();
            }
            exitCode = em.getExitCode();
            String output = em.getMessage();
            emList.add(em);
            if (exitCode != 0) {
                System.out.println("运行失败" + output);
                // 获取错误信息
                System.out.println(em.getMessage());
            } else System.out.println("运行成功" + output);
        }

        // 4. 文件删除
        if (codeFile.getParentFile().exists()) {
            boolean b = FileUtil.del(codeFile.getParentFile());
            System.out.println("删除" + (b ? "成功" : "失败"));
        }

        // 5. 整理结果
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        List<String> outputList = new ArrayList<>();
        Long time = -1L;
        for (ExecuteMessage i : emList) {
            outputList.add(i.getMessage());
            if (i.getTime() != null) time = Math.max(time, i.getTime());
            if (i.getExitCode() != 0) {
                executeCodeResponse.setResult(i.getExitCode());
            }
        }
        executeCodeResponse.setOutput(outputList);
        executeCodeResponse.setResult(Math.max(0, exitCode));

        return executeCodeResponse;
    }

    // 错误响应
    private ExecuteCodeResponse getErrorResponse(Throwable e) {
        ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();
        executeCodeResponse.setOutput(null);
        executeCodeResponse.setResult(13);
        return executeCodeResponse;
    }
}




